package org.budo.dubbo.protocol.http.dispatcher.servlet;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.budo.dubbo.protocol.http.Consts;
import org.budo.dubbo.protocol.http.exception.BudoRuntimeException;
import org.budo.dubbo.protocol.http.invocation.adapter.InvocationAdapter;
import org.budo.dubbo.protocol.http.invocation.adapter.impl.DubboRpcInvocationAdapter;
import org.budo.dubbo.protocol.http.invocation.adapter.impl.WebHttpInvocationAdapter;
import org.budo.dubbo.protocol.http.util.BudoBeanUtil;
import org.budo.dubbo.protocol.http.view.render.ViewRender;
import org.budo.dubbo.protocol.http.view.render.budo.BudoWebHttpJsonViewRender;
import org.budo.dubbo.protocol.http.view.render.impl.DubboViewRender;

import com.alibaba.dubbo.common.utils.StringUtils;

import lombok.Getter;
import lombok.Setter;

/**
 * @author li
 */
@Getter
@Setter
public abstract class AbstractBudoDubboHttpProtocolDispatcherServlet extends HttpServlet {
    private static final long serialVersionUID = -4269612113229235175L;

    private static final DubboRpcInvocationAdapter DUBBO_RPC_INVOCATION_ADAPTER = new DubboRpcInvocationAdapter();

    private static final DubboViewRender DUBBO_VIEW_RENDER_INSTANCE = new DubboViewRender();

    private String defaultViewRender = BudoWebHttpJsonViewRender.class.getName();

    private String defaultInvocationAdapter = WebHttpInvocationAdapter.class.getName();

    protected InvocationAdapter getInvocationAdapter(HttpServletRequest request) {
        String invocationAdapterTypeName = request.getHeader(Consts.HeaderKey.InvocationAdapter);
        if (StringUtils.isEmpty(invocationAdapterTypeName)) {
            invocationAdapterTypeName = this.getDefaultInvocationAdapter();
        }

        InvocationAdapter invocationAdapter = null;
        if (StringUtils.isEmpty(invocationAdapterTypeName) || DubboRpcInvocationAdapter.class.getName().equals(invocationAdapterTypeName)) {
            invocationAdapter = DUBBO_RPC_INVOCATION_ADAPTER;
        } else {
            invocationAdapter = (InvocationAdapter) BudoBeanUtil.getOrInitBeanCached(invocationAdapterTypeName);
        }

        return invocationAdapter;
    }

    private ViewRender getViewRender(HttpServletRequest request) {
        String viewRenderTypeName = request.getHeader(Consts.HeaderKey.ViewRender); // 客户端指定的

        if (StringUtils.isEmpty(viewRenderTypeName)) {
            viewRenderTypeName = this.getDefaultViewRender(); // 服务器端默认的
        }

        // 如果客户端未指定, 服务端也无默认值，则采用全局默认值
        ViewRender viewRender = null;
        if (StringUtils.isEmpty(viewRenderTypeName) || DubboViewRender.class.getName().equals(viewRenderTypeName)) {
            viewRender = DUBBO_VIEW_RENDER_INSTANCE;
        } else {
            viewRender = (ViewRender) BudoBeanUtil.getOrInitBeanCached(viewRenderTypeName); // 这里带缓存
        }
        return viewRender;
    }

    protected void render(HttpServletRequest request, HttpServletResponse response, Object result) {
        ViewRender viewRender = null;
        try {
            viewRender = this.getViewRender(request);

            viewRender.renderView(new ServletProtocolRequest(request), new ServletProtocolResponse(response), result);
        } catch (Throwable e) {
            String message = "#78 renderView error, result=" + result + ", viewRender=" + viewRender //
                    + ", request=" + request //
                    + ", requestURI=" + request.getRequestURI() //
                    + ", remoteAddr=" + request.getRemoteAddr() //
                    + ", userAgent=" + request.getHeader("User-Agent");
            throw new BudoRuntimeException(message, e);
        }
    }
}
